home *** CD-ROM | disk | FTP | other *** search
-
- /******************************* strlist.c *********************************
-
- Purpose: String list abstract data type implementation.
-
- Notes: This module implements a straightforward string ordered list
- abstract data type. It is optimized for appending and deleting
- from the end of the list. Since they are ordered lists, string
- lists may be sorted, and their members are addressed by ordinal
- position (starting from 0).
- **/
-
- #include <stdio.h>
- #include <memory.h>
- #include <malloc.h>
- #include <string.h>
-
- #include "strlist.h"
-
- /******************************************************************************/
- /****************** Private Defines and Data Structures *******************/
-
- #define FALSE 0
- #define TRUE 1
- #define EOS '\0'
-
- #define INCREMENT 32 /* increase size by this much */
- #define MAX_LINE 128 /* when reading text files */
-
- typedef struct _StrListStruct {
-
- short size; /* current length of the list */
- short max_size; /* room for this many strings */
- char **string; /* the string array */
-
- } StrListStruct;
-
- /********* GetMemory and FreeMemory Macros ********/
-
- #define GetMemory(b,s) ( (b) ? realloc(b,s) : malloc(s) )
- #define FreeMemory(b) ( (void)free( b ) )
-
- /******************************************************************************/
- /********************** Private Routine Declarations **********************/
-
- #ifdef __STDC__
-
- static int ExpandArray( StrList list );
- static void ISort( char *string, int lb, int ub );
- static void QSort( char **string, int lb, int ub );
-
- #else
-
- static int ExpandArray( /* list */ );
- static void ISort( /* string, lb, ub */ );
- static void QSort( /* string, lb, ub */ );
-
- #endif
-
- /*FN**************************************************************************
-
- ExpandArray( list )
-
- Returns: int -- TRUE (1) on success, FALSE (0) otherwise
-
- Purpose: Increase the string array to hold more data
-
- Plan: Part 1: Increase the maximum list size to its new value
- Part 2: Allocate a new chunk of memory
- Part 3: Return an indication of success
-
- Notes: None
- **/
-
- static int
- ExpandArray( list )
- StrList list; /* in: string list whose string array is enlarged */
- {
-
- /* Part 1: Increase the maximum list size to its new value */
- list->max_size += INCREMENT;
-
- /* Part 2: Allocate a new chunk of memory */
- list->string = (char **)GetMemory( (char *)list->string,
- (list->max_size*sizeof(char *)) );
-
- /* Part 3: Return an indication of success */
- return( (list->string) ? TRUE : FALSE );
-
- } /* ExpandArray */
-
- /*FN**************************************************************************
-
- ISort( string, lb, ub )
-
- Returns: void
-
- Purpose: Insertion sort a string array forward using strcmp ordering
-
- Plan: Part 1: Put smallest in place as a sentinal
- Part 2: Insert as necessary
-
- Notes: None
- **/
-
- static void
- ISort( string, lb, ub )
- char **string; /* in/out: string array sorted */
- int lb,ub; /* in: array bounds for sort */
- {
- register int i,j; /* for scanning through the list */
- char *tmp; /* for swaps */
-
- /* Part 1: Put smallest in place as a sentinal */
- for ( j = lb, i = lb+1; i <= ub; i++ )
- if ( 0 < strcmp(string[j],string[i]) ) j = i;
- tmp = string[lb]; string[lb] = string[j]; string[j] = tmp;
-
- /* Part 2: Insert as necessary */
- for ( i = lb+2; i <= ub; i++ )
- {
- tmp = string[i];
- for ( j = i; 0 < strcmp(string[j-1],tmp); j-- ) string[j] = string[j-1];
- string[j] = tmp;
- }
-
- } /* ISort*/
-
- /*FN**************************************************************************
-
- QSort( string, lb, ub )
-
- Returns: void
-
- Purpose: Quicksort an array of strings forward using strcmp ordering
-
- Plan: Part 1: Use insertion sort of the list is short
- Part 2: Do median of three pivot value selection
- Part 3: Put the pivot out of the way at the top
- Part 5: Swap the pivot back into the mid of the list
- Part 6: Recursively sort the sublists
-
- Notes: Standard quicksort function with the two main enhancements:
- median of three partitioning to find a good pivot value,
- and sorting small arrays with insertion sort.
- **/
-
- static void
- QSort( string, lb, ub )
- char **string; /* in/out: string array sorted */
- int lb,ub; /* in: array bounds for sort */
- {
- register int lft; /* list pointer that closes from the left */
- register int rgt; /* list pointer that closes from the right */
- register int mid; /* index of the median of three value */
- char *tmp; /* for string pointer swaps */
- char *pivot; /* the pivot value string */
-
- /* Part 1: Use insertion sort of the list is short */
- if ( ub-lb < 12 ) { ISort( string, lb, ub ); return; }
-
- /* Part 2: Do median of three pivot value selection */
- mid = (lb+ub)/2;
- if ( strcmp(string[mid],string[lb]) < 0 )
- { tmp = string[mid]; string[mid] = string[lb]; string[lb] = tmp; }
- if ( strcmp(string[ub],string[mid]) < 0 )
- { tmp = string[mid]; string[mid] = string[ub]; string[ub] = tmp; }
- if ( strcmp(string[mid],string[lb]) < 0 )
- { tmp = string[mid]; string[mid] = string[lb]; string[lb] = tmp; }
-
- /* Part 3: Put the pivot out of the way at the top */
- tmp = string[mid]; string[mid] = string[ub-1]; string[ub-1] = tmp;
-
- /* Part 4: Partition around the pivot value */
- lft = lb;
- rgt = ub-1;
- pivot = string[ub-1];
- do
- {
- do lft++; while ( strcmp(string[lft],pivot) < 0 );
- do rgt--; while ( strcmp(pivot,string[rgt]) < 0 );
- tmp = string[lft]; string[lft] = string[rgt]; string[rgt] = tmp;
- }
- while ( lft < rgt );
-
- /* Part 5: Swap the pivot back into the mid of the list */
- string[rgt] = string[lft]; string[lft] = string[ub-1]; string[ub-1] = tmp;
-
- /* Part 6: Recursively sort the sublists */
- QSort( string, lb, lft-1 );
- QSort( string, rgt+1, ub );
-
- } /* QSort */
-
- /******************************************************************************/
- /********************** Public Routine Declarations ***********************/
-
- /*FN***************************************************************************
-
- StrListAppend( list, string )
-
- Returns: void
-
- Purpose: Place a string on the end of a string list
-
- Plan: Part 1: Standard parameter sanity check
- Part 2: Expand the list as necessary
- Part 3: Append the new string to the tail
-
- Notes: None
- **/
-
- void
- StrListAppend( list, string )
- StrList list; /* in/out: list appended to */
- char *string; /* in: the appended string */
- {
- int length; /* of the added string and its terminator */
-
- /* Part 1: Standard parameter sanity check */
- if ( !list || !string ) return;
-
- /* Part 2: Expand the list as necessary */
- if ( (list->size == list->max_size) && !ExpandArray(list) ) return;
-
- /* Part 3: Append the new string to the tail */
- length = strlen( string ) + 1;
- list->string[list->size] = GetMemory( NULL, length );
- (void)memcpy( list->string[list->size], string, length );
- list->size++;
-
- } /* StrListAppend */
-
- /*FN***************************************************************************
-
- StrListAppendFile( list, filename )
-
- Returns: void
-
- Purpose: Place all lines from a file on the end of a string list
-
- Plan: Part 1: Standard parameter sanity check
- Part 2: Expand the list as necessary
- Part 3: Append the new string to the tail
-
- Notes: None
- **/
-
- void
- StrListAppendFile( list, filename )
- StrList list; /* in/out: list appended to */
- char *filename; /* in: the appended file */
- {
- FILE *file; /* file handle for the text input file */
- char buffer[MAX_LINE]; /* for storing text input file lines */
- int length; /* of the added string and its terminator */
- register int i; /* for looping through the TextBlock lines */
-
- /* Part 1: Standard parameter sanity check */
- if ( !list || !filename ) return;
-
- /* Part 2: Open the text input file; check for error */
- if ( NULL == (file = fopen(filename,"r")) ) return;
-
- /* Part 3: Append to the list, checking for errors */
- while ( NULL != fgets(buffer,MAX_LINE,file) )
- {
- if ( (list->size == list->max_size) && !ExpandArray(list) ) return;
-
- i = list->size;
- length = strlen( buffer );
- list->string[i] = GetMemory( NULL, (unsigned)length );
- if ( NULL == list->string[i] ) return;
- (void)memcpy( list->string[i], buffer, length );
- list->string[i][length-1] = EOS;
- list->size++;
- }
-
- /* Part 4: Close the text input file */
- (void)fclose( file );
-
- } /* StrListAppendFile */
-
- /*FN***************************************************************************
-
- StrListCreate()
-
- Returns: StrList -- a new structure, or NULL on failure
-
- Purpose: Allocate and initialize a new string list structure
-
- Plan: Part 1: Allocate space for the string list object
- Part 2: Initialize the structure fields
- Part 3: Return the new string list
-
- Notes: None
- **/
-
- StrList
- StrListCreate()
- {
- StrList list; /* the new list returned */
-
- /* Part 1: Allocate space for the string list object */
- if ( !(list = (StrList)GetMemory(NULL,sizeof(StrListStruct))) )
- return( NULL );
-
- /* Part 2: Initialize the structure fields */
- list->string = NULL;
- list->size = list->max_size = 0;
- if ( !ExpandArray(list) )
- { FreeMemory( (char *)list ); return( NULL ); }
-
- /* Part 3: Return the new string list */
- return( list );
-
- } /* StrListCreate */
-
- /*FN***************************************************************************
-
- StrListDestroy( list )
-
- Returns: void
-
- Purpose: Deallocate the space used for a string list
-
- Plan: Part 1: Standard parameter sanity check
- Part 2: Free all the space
-
- Notes: None
- **/
-
- void
- StrListDestroy( list )
- StrList list; /* in: the list destroyed */
- {
- register int i; /* for scanning through the list */
-
- /* Part 1: Standard parameter sanity check */
- if ( !list ) return;
-
- /* Part 2: Free all the space */
- for ( i = 0; i < list->size; i++ ) FreeMemory( (char *)(list->string[i]) );
- FreeMemory( (char *)list );
-
- } /* StrListDestroy */
-
- /*FN***************************************************************************
-
- StrListEqual( list1, list2 )
-
- Returns: int -- TRUE if the lists are equivalent, FALSE otherwise
-
- Purpose: See if two lists have identical elements
-
- Plan: Part 1: Say not equal if the parameters are bad
- Part 2: Say not equal if sizes are different
- Part 3: Compare lists element by element
- Part 4: Say equal if everything checks out
-
- Notes: None
- **/
-
- int
- StrListEqual( list1, list2 )
- StrList list1,list2; /* in: lists compared */
- {
- register int i; /* for scanning through the lists */
-
- /* Part 1: Say not equal if the parameters are bad */
- if ( !list1 || !list2 ) return( FALSE );
-
- /* Part 2: Say not equal if sizes are different */
- if ( list1->size != list2->size ) return( FALSE );
-
- /* Part 3: Compare the lists element by element */
- for ( i = 0; i < list1->size; i++ )
- if ( *(list1->string[i]) != *(list2->string[i]) )
- return( FALSE );
- else if ( 0 != strcmp(list1->string[i],list2->string[i]) )
- return( FALSE );
-
- /* Part 5: Say equal if everything checks out */
- return( TRUE );
-
- } /* StrListEqual */
-
- /*FN***************************************************************************
-
- StrListPeek( list, index )
-
- Returns: char * -- pointer to the requested string; NULL on error
-
- Purpose: Peek a string by its list index
-
- Plan: Part 1: Standard parameter sanity check
- Part 2: Return the requested string
-
- Notes: Note that this function is a hole in the data type encapsulation:
- it should return a copy, but this would force the consumer to
- deallocate the string. Design call.
- **/
-
- char *
- StrListPeek( list, index )
- StrList list; /* in: list retrieved from */
- int index; /* in: which string to fetch */
- {
- /* Part 1: Standard parameter sanity check */
- if ( !list || (index < 0) || (list->size <= index) ) return( NULL );
-
- /* Part 2: Return the requested string */
- return( list->string[index] );
-
- } /* StrListPeek */
-
- /*FN***************************************************************************
-
- StrListSize( list )
-
- Returns: int -- the size of the list, 0 on error
-
- Purpose: Grab the list size
-
- Plan: Return the list size field
-
- Notes: None
- **/
-
- int
- StrListSize( list )
- StrList list; /* in: list queried */
- {
-
- if ( !list ) return( 0 ); else return( list->size );
-
- } /* StrListSize */
-
- /*FN***************************************************************************
-
- StrListSort( list )
-
- Returns: void
-
- Purpose: Sort a single string list using strcmp ordering
-
- Plan: Part 1: Do parameter sanity checks, then sort
-
- Notes: None
- **/
-
- void
- StrListSort( list )
- StrList list; /* in/out: list sorted */
- {
- /* Part 1: Do parameter sanity checks, then sort */
- if ( !list ) return;
- QSort( list->string, 0, list->size-1 );
-
- } /* StrListSort */
-
- /*FN***************************************************************************
-
- StrListUnique( list )
-
- Returns: void
-
- Purpose: Sort a single string list using strcmp ordering, then remove
- duplicates.
-
- Plan: Part 1: Do parameters sanity checks
- Part 2: Sort the list
- Part 3: Remove duplicate strings
-
- Notes: None
- **/
-
- void
- StrListUnique( list )
- StrList list; /* in/out: list sorted and uniqued */
- {
- register i,j; /* counters for copying down over duplicates */
-
- /* Part 1: Do parameter sanity checks */
- if ( !list ) return;
-
- /* Part 2: Sort the list */
- QSort( list->string, 0, list->size-1 );
-
- /* Part 3: Remove duplicate strings */
- if ( 1 < list->size )
- {
- for ( j = 0, i = 1; i < list->size; i++ )
- {
- if ( 0 == strcmp(list->string[i],list->string[j]) )
- (void)free( list->string[j] );
- else
- j++;
- if ( j < i ) list->string[j] = list->string[i];
- }
- list->size = j + 1;
- }
-
- } /* StrListUnique */
-
-